﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.Linq;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using Nop.Core;
using Nop.Core.Domain.Common;
using Nop.Core.Domain.Customers;
using Nop.Core.Domain.Orders;
using Nop.Core.Domain.Payments;
using Nop.Core.Domain.Shipping;
using Nop.Core.Http.Extensions;
using Nop.Services.Common;
using Nop.Services.Customers;
using Nop.Services.Directory;
using Nop.Services.Localization;
using Nop.Services.Logging;
using Nop.Services.Orders;
using Nop.Services.Payments;
using Nop.Services.Plugins;
using Nop.Services.Shipping;
using Nop.Web.Areas.App.Models;
using Nop.Web.Extensions;
using Nop.Web.Factories;
using Nop.Web.Framework.Controllers;
using Nop.Web.Framework.Mvc.Filters;
using Nop.Web.Framework.Security;
using Nop.Web.Models.Checkout;
using Nop.Web.Models.Common;

namespace Nop.Web.Areas.App.Controllers
{
    public class CheckoutController : BaseAppController
    {
        #region Fields

        private readonly AddressSettings _addressSettings;
        private readonly CustomerSettings _customerSettings;
        private readonly IAddressAttributeParser _addressAttributeParser;
        private readonly IAddressService _addressService;
        private readonly ICheckoutModelFactory _checkoutModelFactory;
        private readonly ICountryService _countryService;
        private readonly ICustomerService _customerService;
        private readonly IGenericAttributeService _genericAttributeService;
        private readonly ILocalizationService _localizationService;
        private readonly ILogger _logger;
        private readonly IOrderProcessingService _orderProcessingService;
        private readonly IOrderService _orderService;
        private readonly IPaymentService _paymentService;
        private readonly IPluginFinder _pluginFinder;
        private readonly IShippingService _shippingService;
        private readonly IShoppingCartService _shoppingCartService;
        private readonly IStateProvinceService _stateProvinceService;
        private readonly IStoreContext _storeContext;
        private readonly IWebHelper _webHelper;
        private readonly IWorkContext _workContext;
        private readonly OrderSettings _orderSettings;
        private readonly PaymentSettings _paymentSettings;
        private readonly RewardPointsSettings _rewardPointsSettings;
        private readonly ShippingSettings _shippingSettings;
        private readonly IAddressModelFactory _addressModelFactory;
        #endregion

        #region Ctor

        public CheckoutController(AddressSettings addressSettings,
            CustomerSettings customerSettings,
            IAddressAttributeParser addressAttributeParser,
            IAddressService addressService,
            ICheckoutModelFactory checkoutModelFactory,
            ICountryService countryService,
            ICustomerService customerService,
            IGenericAttributeService genericAttributeService,
            ILocalizationService localizationService,
            ILogger logger,
            IOrderProcessingService orderProcessingService,
            IOrderService orderService,
            IPaymentService paymentService,
            IPluginFinder pluginFinder,
            IShippingService shippingService,
            IShoppingCartService shoppingCartService,
            IStateProvinceService stateProvinceService,
            IStoreContext storeContext,
            IWebHelper webHelper,
            IWorkContext workContext,
            OrderSettings orderSettings,
            PaymentSettings paymentSettings,
            RewardPointsSettings rewardPointsSettings,
            ShippingSettings shippingSettings,
            IAddressModelFactory addressModelFactory)
        {
            this._addressSettings = addressSettings;
            this._customerSettings = customerSettings;
            this._addressAttributeParser = addressAttributeParser;
            this._addressService = addressService;
            this._checkoutModelFactory = checkoutModelFactory;
            this._countryService = countryService;
            this._customerService = customerService;
            this._genericAttributeService = genericAttributeService;
            this._localizationService = localizationService;
            this._logger = logger;
            this._orderProcessingService = orderProcessingService;
            this._orderService = orderService;
            this._paymentService = paymentService;
            this._pluginFinder = pluginFinder;
            this._shippingService = shippingService;
            this._shoppingCartService = shoppingCartService;
            this._stateProvinceService = stateProvinceService;
            this._storeContext = storeContext;
            this._webHelper = webHelper;
            this._workContext = workContext;
            this._orderSettings = orderSettings;
            this._paymentSettings = paymentSettings;
            this._rewardPointsSettings = rewardPointsSettings;
            this._shippingSettings = shippingSettings;
            this._addressModelFactory = addressModelFactory;
        }

        #endregion


        #region utils


        Dictionary<string, object> ToDict(object obj)
        {
            Dictionary<string, object> nvc = new Dictionary<string, object>();
            var type = obj.GetType();
            var props = type.GetProperties();
            foreach (var prop in props)
            {
                var value = prop.GetValue(obj);

                if (value == null || string.IsNullOrEmpty(value.ToString()))
                {
                    continue;
                }
                nvc[prop.Name] = value == null ? null : value.ToString();
            }
            return nvc;
        }

        List<ShoppingCartItem> GetCart(string cartIds)
        {
            if (string.IsNullOrEmpty(cartIds))
            {
                return null;
            }
            var cartIdList = cartIds.Split(",").Select(s => int.Parse(s)).ToList();
            if (cartIdList.Count < 1)
            {
                return null;
            }
            var cart = _workContext.CurrentCustomer.ShoppingCartItems.Where(s => cartIdList.Contains(s.Id)).ToList();
            if (cart.Count < 1)
            {
                return null;
            }
            return cart;
        }


        #endregion

        public IActionResult Confirm(string cartIds, int addressId, string shippingOptionKey, string memo)
        {

            if (!_workContext.CurrentCustomer.IsRegistered())
                return Json(new AppResult
                {
                    Code = 999,
                    Message = "您还没有登录"
                });

            var cart = GetCart(cartIds);
            if (cart == null)
            {
                return Json(new AppResult
                {
                    Code = 500,
                    Message = "购物车不能为空"
                });
            }

            var address = _addressService.GetAddressById(addressId);
            if (address == null)
            {
                return Json(new AppResult
                {
                    Code = 500,
                    Message = "地址不存在"
                });
            }
            address.Email = _workContext.CurrentCustomer.Email;
            _workContext.CurrentCustomer.BillingAddress = address;
            _workContext.CurrentCustomer.ShippingAddress = address;

            if (string.IsNullOrEmpty(shippingOptionKey))
            {
                return Json(new AppResult
                {
                    Code = 500,
                    Message = "发货方式不能为空"
                });
            }
            var splittedOption = shippingOptionKey.Split(new[] { "___" }, StringSplitOptions.RemoveEmptyEntries);
            if (splittedOption.Length != 2)
                throw new Exception("Selected shipping method can't be parsed");
            var selectedName = splittedOption[0];
            var shippingRateComputationMethodSystemName = splittedOption[1];

            var shippingOptions = _shippingService.GetShippingOptions(cart, _workContext.CurrentCustomer.ShippingAddress,
                            _workContext.CurrentCustomer, shippingRateComputationMethodSystemName, _storeContext.CurrentStore.Id).ShippingOptions.ToList();
            var shippingOption = shippingOptions
                      .Find(so => !string.IsNullOrEmpty(so.Name) && so.Name.Equals(selectedName, StringComparison.InvariantCultureIgnoreCase));
            if (shippingOption == null)
            {
                return Json(new AppResult
                {
                    Code = 500,
                    Message = "发货方式不能为空"
                });
            }

            _genericAttributeService.SaveAttribute(_workContext.CurrentCustomer, NopCustomerDefaults.SelectedShippingOptionAttribute, shippingOption, _storeContext.CurrentStore.Id);


            string paymentmethod = "HPay.PayPalStandard";


            var paymentMethodInst = _paymentService.LoadPaymentMethodBySystemName(paymentmethod);
            if (paymentMethodInst == null ||
                !_paymentService.IsPaymentMethodActive(paymentMethodInst) ||
                !_pluginFinder.AuthenticateStore(paymentMethodInst.PluginDescriptor, _storeContext.CurrentStore.Id) ||
                !_pluginFinder.AuthorizedForUser(paymentMethodInst.PluginDescriptor, _workContext.CurrentCustomer))
            {
                return Json(new AppResult
                {
                    Code = 500,
                    Message = "服务端未启动聚合支付"
                });
            }


            var processPaymentRequest = paymentMethodInst.GetPaymentInfo(Request.Form);
            if (processPaymentRequest == null)
            {
                return Json(new AppResult
                {
                    Code = 500,
                    Message = "聚合支付验证失败"
                });
            }

            processPaymentRequest.StoreId = _storeContext.CurrentStore.Id;
            processPaymentRequest.CustomerId = _workContext.CurrentCustomer.Id;
            processPaymentRequest.PaymentMethodSystemName = paymentmethod;
            var placeOrderResult = _orderProcessingService.PlaceOrder(processPaymentRequest, cart.Select(s => s.Id).ToList());
            if (placeOrderResult.Success)
            {
                var postProcessPaymentRequest = new PostProcessPaymentRequest
                {
                    Order = placeOrderResult.PlacedOrder
                };
                _paymentService.PostProcessPayment(postProcessPaymentRequest);
                if (!string.IsNullOrEmpty(memo))
                {
                    placeOrderResult.PlacedOrder.OrderNotes.Add(new OrderNote
                    {
                        Note = "用户备注:\n" + memo,
                        DisplayToCustomer = false,
                        CreatedOnUtc = DateTime.UtcNow,
                    });
                    _orderService.UpdateOrder(placeOrderResult.PlacedOrder);
                }
                return Json(new AppResult
                {
                    Code = placeOrderResult.Errors.Count > 0 ? 500 : 0,
                    Message = string.Join(",", placeOrderResult.Errors),
                    Result = new
                    {
                        OrderId = placeOrderResult.PlacedOrder.OrderGuid,
                        PayOrderId = long.Parse(placeOrderResult.PlacedOrder.AuthorizationTransactionId)
                    }
                });
            }
            else
            {
                return Json(new AppResult
                {
                    Code = 500,
                    Message = string.Join(",", placeOrderResult.Errors)
                });
            }

        }

        public IActionResult Info(string cartIds)
        {
            if (!_workContext.CurrentCustomer.IsRegistered())
                return Json(new AppResult
                {
                    Code = 999,
                    Message = "您还没有登录"
                });
            var cart = GetCart(cartIds);
            if (cart == null)
            {
                return Json(new AppResult
                {
                    Code = 500,
                    Message = "购物车不能为空"
                });
            }
            var address = _workContext.CurrentCustomer.Addresses.Where(s => s.IsDefault).FirstOrDefault();
            if (address == null)
            {
                address = _workContext.CurrentCustomer.Addresses.FirstOrDefault();
            }
            var addressModel = new AddressModel();
            _addressModelFactory.PrepareAddressModel(addressModel,
                address: address,
                excludeProperties: false,
                addressSettings: _addressSettings, appMode: true);
            IList<ShippingOption> shippingOptions = null;
            if (address == null)
            {
                shippingOptions = _shippingService.GetAllShippingMethods(0).Select(shippingMethod => new ShippingOption
                {
                    Name = _localizationService.GetLocalized(shippingMethod, x => x.Name),
                    Description = _localizationService.GetLocalized(shippingMethod, x => x.Description),
                    Rate = 0,
                    ShippingRateComputationMethodSystemName = "Shipping.FixedByWeightByTotal"
                }).Take(1).ToList();
            }
            else
            {
                shippingOptions = _shippingService.GetShippingOptions(cart, address,
                       _workContext.CurrentCustomer).ShippingOptions.ToList();
                shippingOptions = shippingOptions.Where(s => s.Rate == 0).ToList();
            }
            return Json(new AppResult
            {
                Result = new
                {
                    Address = addressModel.Id < 1 ? null : addressModel,
                    ShippingOptions = shippingOptions.Select(x => ToDict(x)).ToList()
                }
            });
        }

      
    }
}
